import groovy.transform.Field
@Field final SNAPSHOT_SUFFIX = "-SNAPSHOT"
/**
 * 用 mvn help 获取项目版本
 * pom 中 version 的 -SNAPSHOT 后缀无意义，此次发布是否是 snapshot 版本由配置决定
 * 避免影响 snapshot 版本号的添加，在这里直接去掉 snapshot 后缀
 *
 * @return
 */
def getVersion() {
    def version = sh script: "mvn help:evaluate -Dexpression=project.version  |  grep -v '\\[' | grep -v 'Download'", returnStdout: true
    version = version.trim()
    return isSnapshot(version) ? removeSnapshot(version) : version
}

/**
 * 用 mvn help 获取项目中 revision 的值
 * pom 中 revision 的 -SNAPSHOT 后缀无意义，此次发布是否是 snapshot 版本由配置决定
 * 避免影响 snapshot 版本号的添加，在这里直接去掉 snapshot 后缀
 *
 * @return
 */
def getRevision() {
    def revision = sh script: "mvn help:evaluate -Dexpression=revision  |  grep -v '\\[' | grep -v 'Download'", returnStdout: true
    version = version.trim()
    return isSnapshot(version) ? removeSnapshot(version) : version
}

/**
 * 通过指定的 revision 获取项目版本
 *
 * @param revision
 * @return
 */
def getVersionByRevision(revision) {
    def version = sh script: "mvn help:evaluate -Drevision=${revision} -Dexpression=project.version | grep -v '\\[' | grep -v 'Download'", returnStdout: true
    return version.trim()
}

def isPropertyEmpty(property = "") {
    return property == null || property == "" || property.startsWith("null")
}

/**
 * 根据多位版本号获取基础版本
 * e.g. 1.2.3 -> 1.2, 3.2 -> 3.
 *
 * @param version
 * @return
 */
def getBaseVersion(version) {
    def versionArr = version.split('\\.')
    def lastVersion = versionArr[versionArr.size() - 1]
    def baseVersion = version.substring(0, version.size() - lastVersion.size())
    return baseVersion
}

/**
 * 获取最后一位版本号
 *
 * @param version
 * @param isNewVersion
 * @return
 */
def getLastVersion(version, isNewVersion = false) {
    def versionArr = version.split('\\.')
    def lastVersion = versionArr[versionArr.size() - 1]
    return isNewVersion ? 1 : Integer.parseInt(lastVersion)
}

/**
 * 用新版本号替换末位版本号
 *
 * @param version
 * @param newLastVersion
 * @return
 */
def replaceLastVersion(version, newLastVersion) {
    def versionArr = version.split('\\.')
    versionArr[versionArr.size() - 1] = newLastVersion
    return versionArr.join(".")
}

/**
 * 根据正则匹配，移除版本号后缀
 * e.g. 1.1.1.RELEASE -> 1.1.1, 1.2 -> 1.2
 *
 * @param version
 * @param suffix
 */
def removeSuffix(version) {
    def suffix = getSuffix(version)
    return version.substring(0, version.size() - suffix.size())
}

/**
 * 获取版本号后缀
 * e.g. 1.4 -> "", 1.2.3.RELEASE -> .RELEASE, 2.2.1-SNAPSHOT -> -SNAPSHOT
 *
 * @param version
 * @return
 */
def getSuffix(version) {
    return version.replaceAll("^(\\d+(\\.\\d+)*)", "")
}

/**
 * 将字符串中的 "." 进行转义
 *
 * @param version
 */
def escape(version) {
    return version.replaceAll("\\.", "\\\\.")
}

/**
 * 通过特定 commit log 和 tag，获取最近一次发布的修订版本号
 *
 * @param baseVersion
 * @param versionSuffix
 * @return
 */
def getCurrentRevisionByTag(baseVersion, versionSuffix) {
    def escapeBaseVersion = escape(baseVersion)
    def escapeVersionSuffix = escape(versionSuffix)

    // 通过 git log 获取最近一次以基础版本号和后缀作为 tag 提交的 commit
    // 在展示 tag 的模式下通过 egrep 来匹配之前的相关 tag
    def lastCommit = sh script: "git log --simplify-by-decoration --decorate --all --pretty=oneline " +
            "| egrep 'tag: v${escapeBaseVersion}[[:digit:]]+${escapeVersionSuffix}[)|,]' " +
            "| cut -f '1' -d ' ' | head -1", returnStdout: true
    lastCommit = lastCommit.trim()

    // 如果不存在则说明是全新的大版本，且未发布过任何修订版本，返回 -1
    if (isPropertyEmpty(lastCommit)) {
        return -1
    }
    def latestTag = sh script: "git tag --contains '${lastCommit}' " +
            "| sort -V --reverse " +
            "| egrep 'v${escapeBaseVersion}[[:digit:]]+${escapeVersionSuffix}\$' " +
            "| head -1", returnStdout: true
    def latestVersion = latestTag.replaceAll("v", "").trim()
    latestVersion = removeSuffix(latestVersion)

    // 获取最后一位版本号
    return getLastVersion(latestVersion, false)
}

def isSnapshot(suffix) {
    return suffix.endsWith(SNAPSHOT_SUFFIX)
}

def removeSnapshot(suffix) {
    return suffix.substring(0, suffix.size() - SNAPSHOT_SUFFIX.size())
}

/**
 * 通过 tag 和项目中的大版本号，确定需要发布的版本号
 *
 * @param currentVersion
 * @param revision
 * @param revisionSuffix
 * @return
 */
def getNextVersionByTag(currentVersion, revision, versionSuffix) {
    def baseVersion = getBaseVersion(currentVersion)
    def snapshot = isSnapshot(versionSuffix)
    def suffixWithSnapshot
    def suffixWithoutSnapshot

    if (snapshot) {
        suffixWithSnapshot = versionSuffix
        suffixWithoutSnapshot = removeSnapshot(versionSuffix)
    } else {
        suffixWithSnapshot = versionSuffix + SNAPSHOT_SUFFIX
        suffixWithoutSnapshot = versionSuffix
    }

    // SNAPSHOT 版本是特殊的版本，我们分别取带与不带 SNAPSHOT 的两次最近的版本号来共同决定当前的版本
    def currentRevisionWithSnapshot = getCurrentRevisionByTag(baseVersion, suffixWithSnapshot)
    def currentRevisionWithoutSnapshot = getCurrentRevisionByTag(baseVersion, suffixWithoutSnapshot)
    sh "echo 'current version with snapshot: ${currentRevisionWithSnapshot}'"
    sh "echo 'current version without snapshot: ${currentRevisionWithoutSnapshot}'"

    def currentRevision
    def snapshotTagExisted = false
    if (currentRevisionWithoutSnapshot >= currentRevisionWithSnapshot) {
        // 如果非 SNAPSHOT 版本号较大或者相等，则无论是 SNAPSHOT 还是非 SNAPSHOT 均将修订版本递增 1
        // 包含了均为 -1 的情况
        currentRevision = currentRevisionWithoutSnapshot + 1
    } else {
        // 如果 SNAPSHOT 版本号较大，则 SNAPSHOT 版本继续发布同样的版本号替代之前的 SNAPSHOT 包，
        // 而非 SNAPSHOT 版本则与当前 SNAPSHOT 版本一至，说明这次发布是对 SNAPSHOT 版本的 RELEASE
        currentRevision = currentRevisionWithSnapshot
        if (snapshot) {
            // 如果该次是需要更新 SNAPSHOT 版本，则说明标记该值为 true, 并在打 tag 时做相应处理
            snapshotTagExisted = true
        }
    }

    // 用新的最后一位版本号替换
    def newVersion = replaceLastVersion(revision, currentRevision)
    sh "echo 'New version: ${newVersion}'"
    return [newVersion, snapshotTagExisted]
}
